package io.gitee.zhangbinhub.acp.boot

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator
import io.gitee.zhangbinhub.acp.boot.aspect.RestControllerAspect
import io.gitee.zhangbinhub.acp.boot.base.BaseSpringBootScheduledAsyncTask
import io.gitee.zhangbinhub.acp.boot.component.*
import io.gitee.zhangbinhub.acp.boot.conf.*
import io.gitee.zhangbinhub.acp.boot.exceptions.DefaultWebExceptionHandler
import io.gitee.zhangbinhub.acp.boot.init.InitServer
import io.gitee.zhangbinhub.acp.boot.init.SystemInitialization
import io.gitee.zhangbinhub.acp.boot.init.task.InitTcpServer
import io.gitee.zhangbinhub.acp.boot.init.task.InitUdpServer
import io.gitee.zhangbinhub.acp.boot.interfaces.Listener
import io.gitee.zhangbinhub.acp.boot.interfaces.LogAdapter
import io.gitee.zhangbinhub.acp.boot.socket.base.SocketServerHandle
import io.gitee.zhangbinhub.acp.boot.tools.SpringBeanFactory
import io.netty.handler.codec.ByteToMessageDecoder
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
import org.springframework.context.annotation.Bean
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter

/**
 * @author zhang by 30/07/2019
 * @since JDK 11
 */
@AutoConfiguration(after = [JacksonAutoConfiguration::class], before = [HttpMessageConvertersAutoConfiguration::class])
class AcpComponentAutoConfiguration {
    @Bean
    fun systemInitialization(
        logAdapter: LogAdapter,
        @Autowired(required = false) listenerMap: Map<String, Listener>?,
        properties: TaskSchedulingProperties,
        scheduleConfiguration: ScheduleConfiguration,
        @Autowired(required = false) baseSpringBootScheduledTaskMap: Map<String, BaseSpringBootScheduledAsyncTask>?,
        acpCoreConfiguration: AcpCoreConfiguration,
        tcpServerConfiguration: TcpServerConfiguration,
        udpServerConfiguration: UdpServerConfiguration,
        socketServerHandleList: List<SocketServerHandle>,
        byteToMessageDecoderList: List<ByteToMessageDecoder>
    ) = SystemInitialization(
        logAdapter, SystemControl(
            logAdapter,
            listenerMap,
            TimerTaskSchedulerCtrl(logAdapter, properties, scheduleConfiguration, baseSpringBootScheduledTaskMap)
        ), InitServer(
            logAdapter,
            InitTcpServer(logAdapter, tcpServerConfiguration, socketServerHandleList, byteToMessageDecoderList),
            InitUdpServer(logAdapter, udpServerConfiguration, socketServerHandleList),
            acpCoreConfiguration
        )
    )

    @Bean
    @ConditionalOnMissingBean(SpringBeanFactory::class)
    fun springBeanFactory() = SpringBeanFactory()

    @Bean
    @ConditionalOnMissingBean(XmlMapper::class)
    fun jacksonXmlMapper(builder: Jackson2ObjectMapperBuilder): XmlMapper =
        builder.createXmlMapper(true).build<XmlMapper>().apply {
            this.enable(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)
        }

    @Bean
    @ConditionalOnMissingBean(MappingJackson2XmlHttpMessageConverter::class)
    fun mappingJackson2XmlHttpMessageConverter(builder: Jackson2ObjectMapperBuilder): MappingJackson2XmlHttpMessageConverter =
        MappingJackson2XmlHttpMessageConverter(jacksonXmlMapper(builder))

    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    fun restControllerAspect(
        controllerLogConfiguration: ControllerLogConfiguration, objectMapper: ObjectMapper
    ) = RestControllerAspect(controllerLogConfiguration, objectMapper)

    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    @ConditionalOnMissingBean(FileDownLoadHandle::class)
    fun fileDownLoadHandle(logAdapter: LogAdapter) = FileDownLoadHandle(logAdapter)

    @Bean
    fun defaultWebExceptionHandler() = DefaultWebExceptionHandler()

    @Bean
    fun serverTools() = ServerTools()
}